package com.aka.tools.animation 
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.utils.Timer;
	
	/**
	 * ...
	 * @author Huhanpeng
	 */
	public class TurnToChange extends Sprite 
	{
		public static const DONE:String = "com.aka.tools.animation.TurnToChange.done";
		
		public static const HIGH:int = 50;
		public static const MID:int = 100;
		public static const LOW:int = 200;
		
		//动画精度，单位为毫秒
		protected var _quality:int;
		
		protected var _stage:Stage;
		
		//移动所费时长，单位为毫秒
		protected var _time:int;
		
		//目标对象
		protected var _tOne:DisplayObject;
		protected var _tTwo:DisplayObject;
		
		//目标的父容器及index
		protected var _parentOne:DisplayObjectContainer;
		protected var _parentTwo:DisplayObjectContainer;
		protected var _indexOne:int;
		protected var _indexTwo:int;
		
		
		//目标初始在父对象中的位置
		protected var _localOne:Point;
		protected var _localTwo:Point;
		
		//每次转动的角度
		protected var _rollSpeed:Number;
		
		protected var _timer:Timer;
		
		
		/////////////////////////////////////////////////////////////////////
		//getter setter                                                    //
		/////////////////////////////////////////////////////////////////////
		
		


		/////////////////////////////////////////////////////////////////////
		//构造函数                                                         //
		/////////////////////////////////////////////////////////////////////
		/**
		 * 转动180度交换one和two的位置,开始为start(),完成发送时间DONE
		 * @param	one		待交换对象
		 * @param	two 	待交换对象
		 * @param	stage	舞台
		 * @param	time	动画时常,单位为毫秒
		 * @param	quality	动画精度，越小精度越高，可选HIGH(50),MID(100),LOW(200)
		 */
		public function TurnToChange( one:DisplayObject, two:DisplayObject, stage:Stage, time:int = 500, quality:int = MID)
		{
			init(one, two, stage, time, quality);
		}
		
		protected function init(one:DisplayObject, two:DisplayObject, stage:Stage, time:int, quality:int ):void
		{
			if ( stage == null ) 
			{
				throw new Error("stage不能为null");
			}
			
			if ( one == null || two == null ) 
			{
				throw new Error("移动的两对象不能为null");
			}
			
			mouseEnabled = mouseChildren = false;
			
			_stage = stage;
			_tOne = one;
			_tTwo = two;
			_time = time;
			_quality = quality;
		}
		

		/////////////////////////////////////////////////////////////////////
		//接口                                                             //
		/////////////////////////////////////////////////////////////////////
		
		public function start():void 
		{
			//储存初始数据
			storeState();
			
			//将此容器置于两对象正中间，并把对象转移到此容器
			prepare();
			
			//移动控制部分
			go();
		}
		

		

		
		/////////////////////////////////////////////////////////////////////
		//内部                                                             //
		/////////////////////////////////////////////////////////////////////


		//储存初始数据
		protected function storeState():void 
		{
			if ( _tOne.stage == null || _tTwo.stage == null ) 
			{
				throw new Error("移动的两对象必须在舞台上");
			}
			
			_localOne = new Point(_tOne.x, _tOne.y);
			_localTwo = new Point(_tTwo.x, _tTwo.y);
			
			
			_parentOne = _tOne.parent;
			_parentTwo = _tTwo.parent;
			
			_indexOne = _parentOne.getChildIndex(_tOne);
			_indexTwo = _parentTwo.getChildIndex(_tTwo);
		}

		
		//将此容器置于两对象正中间，并把对象转移到此容器
		protected function prepare():void 
		{
			var globalOne:Point = _parentOne.localToGlobal(_localOne);
			var globalTwo:Point = _parentTwo.localToGlobal(_localTwo);
			
			//将此容器置于两对象正中间,并添加到舞台
			x = (globalOne.x + globalTwo.x) / 2;
			y = (globalOne.y + globalTwo.y) / 2;
			_stage.addChild(this);
			
			_tOne.parent.removeChild(_tOne);
			_tTwo.parent.removeChild(_tTwo);
			
			//将两对象添加到此容器中，相对舞台的位置不变
			_tOne.x = globalOne.x - x;
			_tOne.y = globalOne.y - y;
			
			_tTwo.x = globalTwo.x - x;
			_tTwo.y = globalTwo.y - y;
			
			rotation = 0;
			addChild(_tOne);
			addChild(_tTwo);
		}

		
		//移动控制部分
		protected function go():void 
		{
			var changeNum:int = Math.round( _time / _quality );
			var delay:int = _time / changeNum;
			_rollSpeed = 180 / changeNum;
			
			
			_timer = new Timer(delay, changeNum);
			_timer.addEventListener(TimerEvent.TIMER, onTick);
			_timer.start();
			
		}
		
		private function onTick(e:TimerEvent):void 
		{
			rotation += _rollSpeed;
			if (_timer.currentCount == _timer.repeatCount) 
			{
				clean();
			}
		}
		
		
		//移动结束还原并发动事件
		protected function clean():void 
		{
			_timer.removeEventListener(TimerEvent.TIMER, onTick);
			_stage.removeChild(this);
			
			_tOne.x = _localTwo.x;
			_tOne.y = _localTwo.y;
			try 
			{
				_parentTwo.addChildAt(_tOne, _indexTwo);
			}
			catch(e:Error)
			{
				_parentTwo.addChild(_tOne);
			}
			
			_tTwo.x = _localOne.x;
			_tTwo.y = _localOne.y;
			
			try 
			{
				_parentOne.addChildAt(_tTwo, _indexOne);
			}
			catch (e:Error)
			{
				_parentOne.addChild(_tTwo);
			}
			
			
			dispatchEvent(new Event(DONE));
		}
	}

}